Clipping the Axis.VisibleRange on Zoom and Pan
Axis.VisibleRangeLimit
Given a chart with data in the range of 0:10, when you zoom to extents, the axis will have a VisibleRange of 0:10. Sometimes this is not desirable, and you want to clip the Axis.VisibleRange inside the data-range. To do this, you can use the Axis.VisibleRangeLimit property.
For example. Given an axis without any limits (AxisBase.VisibleRangeLimit = null). When we perform ZoomExtents on the parent chart, the XAxis gets the visible range (0;10):
Actual XAxis data range = (0:10) ; XAxis.VisibleRangeLimit = null; XAxis.VisibleRange after ZoomExtents = (0:10)
After setting XAxis.VisibleRangeLimit = (1:9) and using ZoomExtents we now get an XAxis.VisibleRange = (1:9). In other words, zooming has clipped or limited the VisibleRange to (1:9)
NOTE: VisibleRangeLimit does not clip data range when VisibleRangeLimit is greater than data range. In this case after ZoomExtents you’ll get the actual data range.
Declaring Axis.VisibleRangeLimit in XAML
Declaring Axis.VisibleRangeLimit |
Copy Code |
---|---|
<s:NumericAxis VisibleRangeLimit="0, 100" /> |
Declaring Axis.VisibleRangeLimit in XAML / MVVM
Declaring Axis.VisibleRangeLimit |
Copy Code |
---|---|
<s:NumericAxis VisibleRangeLimit="{Binding XLimit}" /> // Then, in your ViewModel private IRange _xLimit = new DoubleRange(0, 100); public IRange XLimit { get { return _xLimit; } set { _xLimit = value; OnPropertyChanged(“XLimit”); } } |
Declaring Axis.VisibleRangeLimit in Code
Declaring Axis.VisibleRangeLimit |
Copy Code |
---|---|
xAxis.VisibleRangeLimit = new DoubleRange(0.0, 100.0); |
Axis.VisibleRangeLimitMode
Another property which can be used to change how the VisibleRangeLimit works is AxisBase.VisibleRangeLimitMode.
- AxisBase.VisibleRangeLimitMode = RangeClipMode.MinMax– (Default) Allow clipping at Min and Max
- AxisBase.VisibleRangeLimitMode = RangeClipMode.Max- Allow clipping only at Max
- AxisBase.VisibleRangeLimitMode = RangeClipMode.Min- Allow clipping only at Min
Use this property if you wish to ensure that one side of the chart is always clipped, while the other side is not. For instance:
Axis.VisibleRangeLimitMode |
Copy Code |
---|---|
<!-- Ensures VisibleRangeLimit of 0 is applied to the VisibleRange.Min --> <!-- The VisibleRange.Max is unbounded --> <s:NumericAxis VisibleRangeLimit="0,0" VisibleRangeLimitMode="Min"/> |
Results in a chart that always sets VisibleRange.Min = 0 when you zoom to extents.
NOTE: VisibleRangeLimit does not clip data range when VisibleRangeLimit is greater than data range. In this case after ZoomExtents you’ll get the actual data range.
Advanced VisibleRange Clipping and Manipulation
Axis.VisibleRangeLimit is a useful API to ensure the axis clips the VisibleRange when zooming to extents. However, it will not stop a user from scrolling outside of that range. To achieve that, you need a small modification:
Clipping Axis.VisibleRange in Code
To clip the VisibleRange and force a certain maximum or minimum, just use the following code:
Clipping Axis.VisibleRange in Code |
Copy Code |
---|---|
axis.VisibleRangeChanged += (s, e) => { // e is VisibleRangeChangedEventArgs // Assuming axis is NumericAxis if (e.NewVisibleRange != null && e.NewVisibleRange.Min < 0) { // Force minimum visiblerange to zero always ((NumericAxis)sender).VisibleRange = new DoubleRange(0, e.NewVisibleRange.Max); } }; |
Clipping Axis.VisibleRange with MVVM
The same can be achieved in MVVM by creating a custom behavior.
Clipping Axis.VisibleRange with MVVM |
Copy Code |
---|---|
public class AxisClippingBehavior : Behavior<AxisBase> { protected override void OnAttached() { base.OnAttached(); AssociatedObject.VisibleRangeChanged +=OnVisibleRangeChanged; } protected override void OnDetaching() { base.OnDetaching(); AssociatedObject.VisibleRangeChanged -= OnVisibleRangeChanged; } private void OnVisibleRangeChanged(object sender, VisibleRangeChangedEventArgs visibleRangeChangedEventArgs) { var visibleRangeLimit = AssociatedObject.VisibleRangeLimit; if (visibleRangeLimit != null) { var limitMode = AssociatedObject.VisibleRangeLimitMode; var range = (IRange)AssociatedObject.VisibleRange.Clone(); range.ClipTo(visibleRangeLimit, limitMode); AssociatedObject.SetCurrentValue(AxisBase.VisibleRangeProperty, range); } } } |
The usage in XAML would then be:
Clipping Axis.VisibleRange with MVVM |
Copy Code |
---|---|
<s:NumericAxis> <i:Interaction.Behaviors> <clipAxis:AxisClippingBehavior /> </i:Interaction.Behaviors> </s:NumericAxis> |
Specifying a Minimum Zoom Level
If you want to constrain zoom depth in your application, the Axis.MinimalZoomConstrain property allows you to constrain changing of axis VisibleRange if its VisibleRange.Diff value is too small. When you use MinimalZoomConstain you define minimal difference between Min and Max of VisibleRange and if this difference < MinimalZoomConstrain then VisibleRange will not change.
Specifying Minimum Zoom Level on a NumericAxis or LogarithmicNumericAxis
Specifying Minimum Zoom Level on a NumericAxis or LogarithmicNumericAxis |
Copy Code |
---|---|
var numericAxis = new NumericAxis(); // Do not allow zooming where VisibleRange.Max-visibleRange.Min // is less than 1E-3 numericAxis.MinimalZoomConstrain = 1E-3; |
Specifying Minimum Zoom Level on a DateTimeAxis or TimeSpanAxis
Specifying Minimum Zoom Level on a DateTimeAxis or TimeSpanAxis |
Copy Code |
---|---|
var dateTimeAxis = new DateTimeAxis(); // Do not allow zooming where VisibleRange.Max-visibleRange.Min // is less than 100ms dateTimeAxis.MinimalZoomConstrain = TimeSpan.FromMilliseconds(100); |
Specifying Minimum Zoom Level on a CategoryDateTimeAxis
Specifying Minimum Zoom Level on a CategoryDateTimeAxis |
Copy Code |
---|---|
var catAxis = new CategoryDateTimeAxis(); // Do not allow zooming where VisibleRange.Max-visibleRange.Min // is less than 10 data-points dateTimeAxis.MinimalZoomConstrain = 10 |